package com.smartwebx.fr.controller;

import java.net.URLDecoder;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.common.base.CharMatcher;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.primitives.Ints;
import com.smartwebx.fr.bean.SimpleUseArgConf;
import com.smartwebx.fr.bean.mysql.PageFreetable;
import com.smartwebx.fr.service.StoredProcService;
import com.smartwebx.fr.service.ckeditor.PageFreeTableService;
import com.smartwebx.fr.service.ckeditor.UseArgConfService;
import com.smartwebx.fr.util.StationFinalFields;

@Controller
@RequestMapping("/freeTable")
public class SmartFreeTableController {
	@Autowired
	private PageFreeTableService pageFreeTableService;

	@Autowired
	private UseArgConfService useArgConfService;

	@Autowired
	private StoredProcService storedProcService;

	@RequestMapping("/getFreeTab")
	@ResponseBody
	public Object getFreeTab(Integer pageId, String freeTabId) throws Exception {
		PageFreetable pageFreeTab = pageFreeTableService
				.getPageFreeTable(freeTabId);
		List<SimpleUseArgConf> simpleUseArgs = useArgConfService
				.getSimpleUseArgConfs(pageId);

		String html = this.getRealTabHtml(pageFreeTab.getFreeTabHtml(),
				simpleUseArgs);
		pageFreeTab.setReadTabHtml(html);

		return ImmutableMap.of("page", pageFreeTab, "simpleUseArgs",
				simpleUseArgs);
	}

	@RequestMapping("/copyFreeTab")
	@ResponseBody
	public Boolean copyFreeTab(Integer pageId, String oldTabId, String newTabId) {
		return pageFreeTableService.copyFreeTab(oldTabId, newTabId, pageId);
	}

	@RequestMapping("/getRealTabHtmlByFreeTabHtml")
	@ResponseBody
	public Object getRealTabHtmlByFreeTabHtml(Integer pageId, String freeTabHtml)
			throws Exception {
		List<SimpleUseArgConf> simpleUseArgs = useArgConfService
				.getSimpleUseArgConfs(pageId);
		String deFreeTabHtml = URLDecoder.decode(freeTabHtml,
				StationFinalFields.DEFAULT_ENCODE);
		String html = this.getRealTabHtml(deFreeTabHtml, simpleUseArgs);

		return ImmutableMap.of("html", html, "simpleUseArgs", simpleUseArgs);
	}

	private String getRealTabHtml(String freeTabHtml,
			List<SimpleUseArgConf> simpleUseArgs) {
		Document doc = Jsoup.parse(freeTabHtml);
		Element findTable = doc.select("table").first();
		findTable.removeAttr("class").removeAttr("style");
		Elements tds = findTable.select("td.dbFun");

		if (!tds.isEmpty()) {
			ExecutorService service = Executors.newFixedThreadPool(10);
			List<BuildRealData> buildReals = Lists.newArrayList();
			for (Element td : tds) {
				buildReals.add(new BuildRealData(simpleUseArgs, td));
			}

			List<Future<String>> futures = null;
			try {
				futures = service.invokeAll(buildReals, 90, TimeUnit.SECONDS);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				service.shutdown();
			}

			int i = 0;
			for (Future<String> f : futures) {
				Element element = tds.get(i);
				element.children().remove();

				boolean isCancell = f.isCancelled();

				if (isCancell) {// 查询超时，取消查询
					element.text("查询超时");
					f.cancel(true);
				} else {
					String val = null;
					try {
						val = f.get();
					} catch (InterruptedException e) {
						e.printStackTrace();
						val = "数据异常";
					} catch (ExecutionException e) {
						e.printStackTrace();
						val = "数据异常";
					}
					element.text(val);
				}
				i++;
			}
		}
		String html = findTable.outerHtml();

		return html;
	}

	public static void main(String args[]) {
		System.out.println(charToInt("G"));
		System.out.println(charToInt("AG"));
	}

	/**
	 * 将两位以内的excel字母转换为数字
	 * 
	 * @param xVal
	 * @return
	 */
	private static int charToInt(String xVal) {
		int x = 0;
		// A-Z
		List<Integer> aZList = ContiguousSet.create(Range.closed(65, 90),
				DiscreteDomain.integers()).asList();
		char[] xChars = xVal.toCharArray();
		if (xChars.length <= 2) {
			boolean next = false;
			for (char c : xChars) {
				if (next) {
					x *= 26;
				}
				Integer i = (int) c;
				x += (aZList.indexOf(i) + 1);
				next = true;
			}
		} else {
			x = -1;
		}
		return x;
	}

	class BuildRealData implements Callable<String> {
		private List<SimpleUseArgConf> simpleUseArgs;
		private Element ele;

		public BuildRealData(List<SimpleUseArgConf> simpleUseArgs, Element ele) {
			this.simpleUseArgs = simpleUseArgs;
			this.ele = ele;
		}

		@Override
		public String call() throws Exception {
			String sql = ele.attr("code");
			String backType = ele.attr("backtype");
			String result = null;
			try {
				if (StringUtils.equals("table", backType)) {
					String points = ele.attr("points");

					if (Strings.isNullOrEmpty(points)) {
						points = "0,0";
					} else {
						points = StringUtils.upperCase(points);
						if (Pattern.matches("[A-Z]+\\d+", points)) {// A1,A10
							String xVal = CharMatcher.JAVA_UPPER_CASE
									.retainFrom(points);
							int y = Ints.tryParse(CharMatcher.DIGIT
									.retainFrom(points));
							int x = charToInt(xVal);
							if (x == -1) {
								points = "0,0";
							} else {
								if (--x < 0)
									x = 0;
								if (--y < 0)
									y = 0;
								points = y + "," + x;
							}
						} else if (!Pattern.matches("\\d+,\\d+", points)) {// 1,1
							points = "0,0";
						}
					}
					result = storedProcService.getSingleData(sql,
							simpleUseArgs, backType, points);
				} else if (StringUtils.equals("signValue", backType)) {
					result = storedProcService.getSingleData(sql,
							simpleUseArgs, backType);
				}
			} catch (Exception e) {
				result = "配置错误";
				e.printStackTrace();
			}
			String val = MoreObjects.firstNonNull(result,
					StationFinalFields.No_Data_Point);
			// ele.children().remove();
			// ele.text(val);

			return val;
		}
	}
}